package cn.com.surker.material.service.impl;

import cn.com.surker.base.system.dao.SysStorageDao;
import cn.com.surker.base.system.vo.SysStorageVo;
import cn.com.surker.common.MessageCenterException;
import cn.com.surker.database.JDBCTemplateCache;
import cn.com.surker.enums.material.BillWeightTypeEnum;
import cn.com.surker.enums.material.MaterialBreedTypeEnum;
import cn.com.surker.enums.system.DataBaseEnum;
import cn.com.surker.lab.dao.LabExpendDao;
import cn.com.surker.lab.vo.LabExpendVo;
import cn.com.surker.material.dao.MainMaterialBillDao;
import cn.com.surker.material.dao.MainMaterialInventoryDao;
import cn.com.surker.material.dao.MainMaterialInventoryDetailDao;
import cn.com.surker.material.dao.MainMaterialWeightDao;
import cn.com.surker.material.entity.MainMaterialBill;
import cn.com.surker.material.entity.MainMaterialInventory;
import cn.com.surker.material.entity.MainMaterialInventoryDetail;
import cn.com.surker.material.service.MaterialInventoryBaseService;
import cn.com.surker.material.service.MaterialInventoryDetailBaseService;
import cn.com.surker.material.vo.MainMaterialWeightVo;
import cn.com.surker.material.vo.MaterialInventoryDetailVo;
import cn.com.surker.oa.dao.OaMaterialDao;
import cn.com.surker.oa.entity.OaMaterial;
import cn.com.surker.spring.RestResultDto;
import cn.com.surker.system.dao.DataSourceInfoDao;
import cn.com.surker.system.entity.DataSourceInfo;
import cn.com.surker.util.DateUtil;
import cn.com.surker.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
* <p>
    * 材料盘存表 服务实现类
    * </p>
*
* @author admin
* @since 2024-12-05
*/
public abstract class MaterialInventoryBaseServiceImpl extends ServiceImpl<MainMaterialInventoryDao, MainMaterialInventory> implements MaterialInventoryBaseService {

    @Resource
    protected MainMaterialInventoryDao materialInventoryDao;
    @Resource
    protected DataSourceInfoDao dsDao;
    @Resource
    protected MainMaterialWeightDao materialWeightDao;
    @Resource
    protected LabExpendDao labExpendDao;
    @Resource
    protected OaMaterialDao materialDao;
    @Resource
    protected MainMaterialInventoryDetailDao inventoryDetailDao;
    @Resource
    protected MainMaterialBillDao materialBillDao;

    /**
     * 云端分页查询
     * @param orgId
     * @param today
     * @param searchVal
     * @param startTime
     * @param endTime
     * @return
     */
    public IPage findCloudPage(Long orgId, String today, Integer breedType, String searchVal,
                               String startTime, String endTime, Integer offset, Integer limit) {
        if (StringUtils.isNull(orgId))
            return null;
        DataSourceInfo ds = dsDao.queryDSByOriginIdV1(orgId, DataBaseEnum.MYSQL.getCode());
        if (ds == null || ds.getStatus() == 1 || ds.getType() != 0)
            return null;
        PageHelper.offsetPage(offset, limit);
        QueryWrapper<MainMaterialInventory> query = new QueryWrapper<>();
        query.eq("org_id", orgId);
        query.eq("status", 0);
        if (!StringUtils.isNull(today))
            query.eq("today", today);
        if (!StringUtils.isNull(breedType))
            query.eq("breed_type", breedType);
        if (!StringUtils.isNull(startTime))
            query.ge("start_time", startTime);
        if (!StringUtils.isNull(endTime))
            query.lt("start_time", endTime);
        query.orderByDesc("today");
        query.orderByAsc("breed_type");
        IPage<MainMaterialInventory> iPage = materialInventoryDao.selectPage(new Page<>((offset + limit) /limit, limit),query);

        if (!StringUtils.isNull(iPage.getRecords())) {
            PageInfo pageInfo = new PageInfo(iPage.getRecords());
            if (!StringUtils.isNull(pageInfo.getTotal()))
                iPage.setTotal(pageInfo.getTotal());
        }
        return iPage;
    }

    /**
     * 更新盘存汇总
     * @return
     */
    public RestResultDto updateInventory(Long id, Double addWeight, Double handExpend, String remark, String creator) {
        if (StringUtils.isNull(id))
            throw new MessageCenterException("参数错误");
        MainMaterialInventory inventory = materialInventoryDao.selectById(id);
        if (inventory == null || inventory.getStatus() == 1)
            throw new MessageCenterException("实例不存在或已被禁用");
        if (!StringUtils.isNull(inventory.getIsCheck()) && (inventory.getIsCheck() == 1 || inventory.getIsFinance() == 1))
            throw new MessageCenterException("已审核的数据不允许修改");
        if (!StringUtils.isNull(addWeight)) {
            inventory.setAddWeight(addWeight);
        }

        Double sumExpend = StringUtils.convertDouble(inventory.getSumExpend());
        if (!StringUtils.isNull(handExpend)) {//手动消耗
            inventory.setHandExpend(handExpend);
            sumExpend = inventory.getHandExpend() + StringUtils.convertDouble(inventory.getProExpend());
            inventory.setSumExpend(StringUtils.formatDouble(sumExpend, 1));
//            inventory.setAdjustExpend(StringUtils.formatDouble(sumExpend, 1));
        }
        if (!StringUtils.isNull(remark))
            inventory.setRemark(remark);
        Date nowDate = new Date();
        inventory.setUpdateTime(nowDate);
        inventory.setUpdator(inventory.getUpdator());
        //本月帐存=(上月结余+本月进货)-本月消耗；
        // 盈亏=本月盘存-本月帐存；调整后消耗=(上月结余+本月进货)-本月盘存；
        // 其中本月消耗=拌台系统消耗数或理论计算消耗数
        Double lastStorage = StringUtils.convertDouble(inventory.getLastStorage());//上月上月账存
        Double inventoryDosage = StringUtils.convertDouble(inventory.getInventory());//盘存值
        Double sumWeight = StringUtils.convertDouble(inventory.getBuyWeight()) + StringUtils.convertDouble(inventory.getAddWeight());
        Double monthStorage = lastStorage + sumWeight - sumExpend;
        Double difference = StringUtils.formatDouble(inventoryDosage - monthStorage, 1);//盈亏
        Double adjustExpend = lastStorage + sumWeight - inventoryDosage;
        inventory.setMonthStorage(StringUtils.formatDouble(monthStorage, 1));//本月账存
        inventory.setDifference(difference);
        inventory.setAdjustExpend(adjustExpend);
        Integer code = materialInventoryDao.updateById(inventory);
        if (code > 0)
            return RestResultDto.success("更新成功");
        throw new MessageCenterException("更新错误");
    }

    /**
     * 更新明细状态
     * @param id
     * @param status
     * @param creator
     * @return
     */
    public RestResultDto updateStatus(Long id, Integer status, String creator) {
        if (StringUtils.isNull(id))
            throw new MessageCenterException("参数错误");

        MainMaterialInventory inventory = materialInventoryDao.selectById(id);
        if (inventory == null || inventory.getStatus() == 1)
            throw new MessageCenterException("实例不存在或已被禁用");

        if (!StringUtils.isNull(inventory.getIsCheck()) && (inventory.getIsCheck() == 1 || inventory.getIsFinance() == 1))
            throw new MessageCenterException("已审核的数据不允许修改");
        inventory.setStatus(status);
        inventory.setUpdator(creator);
        inventory.setUpdateTime(new Date());
        Integer code = materialInventoryDao.updateById(inventory);
        if (code > 0)
            return RestResultDto.success("更新成功");
        throw new MessageCenterException("更新错误");
    }
    /**
     * 更新状态
     * @return
     */
    public RestResultDto updateStatus(Long orgId, String today, Integer status, String creator, String remark) {
        if (StringUtils.isAllParamNull(orgId, today, status))
            throw new MessageCenterException("参数错误");
        QueryWrapper<MainMaterialInventory> query = new QueryWrapper<>();
        query.eq("status", 0);
        query.eq("is_check", 1);
        query.eq("today", today);
        query.eq("org_id", orgId);
        Integer total = materialInventoryDao.selectCount(query);
        if (total > 0)
            throw new MessageCenterException("存在已审核的数据,不支持数据同步");
        UpdateWrapper<MainMaterialInventory> uw = new UpdateWrapper<>();
        uw.set("status", status);
        uw.set("update_time", DateUtil.convertString(new Date()));
        if (!StringUtils.isNull(creator))
        uw.set("updator", creator);
        if (!StringUtils.isNull(remark))
            uw.set("remark", remark);
        uw.eq("org_id", orgId);
        uw.eq("today", today);
        uw.eq("status", 0);

        materialInventoryDao.update(new MainMaterialInventory(), uw);
        return RestResultDto.success("更新成功~！");
    }

    /**
     * 补收及任务计算
     * @param orgId
     * @param today
     * @param creator
     * @return
     */
    public RestResultDto calcInventory(Long orgId, String today, String startTime, String endTime, Integer breedType,
                                String creator) {
        if (StringUtils.isAllParamNull(orgId, today))
            throw new MessageCenterException("参数错误");
        DataSourceInfo ds = dsDao.queryDSByOriginIdV1(orgId, DataBaseEnum.MYSQL.getCode());
        if (ds == null || ds.getStatus() == 1 || ds.getType() != 0)
            throw new MessageCenterException("ERP数据源错误");
        Integer checkTotal = inventoryDetailDao.findCheckTotal(ds.getCode(), orgId, today, 1, null);
        if (checkTotal > 0)
            throw new MessageCenterException(today + "材料盘存明细报表已审核,不能再进行系统计算");
        checkTotal = inventoryDetailDao.findCheckTotal(ds.getCode(), orgId, today, null, 1);
        if (checkTotal > 0)
            throw new MessageCenterException(today + "材料盘存明细报表已审核,不能再进行系统计算");

        QueryWrapper<OaMaterial> query = new QueryWrapper<>();
        query.eq("status", 0);
        query.inSql("id", "select material_id from main_material_contract_price " +
                "where status = 0 and org_id =" +orgId + " group by material_id");
        if (!StringUtils.isNull(breedType))
            query.eq("breed_type", breedType);
        List<OaMaterial> materialList = materialDao.selectList(query);
        if (materialList == null || materialList.size() == 0)
            throw new MessageCenterException("没有任何材料信息");
        Map<Long, OaMaterial> materialMap = new HashMap<>();
        for (int i = 0; i < materialList.size(); i++) {
            OaMaterial material = materialList.get(i);
            materialMap.put(material.getId(), material);
        }
        Map<Integer, String> breedTypeMap = new HashMap<>();
        for (int i = 0; i < MaterialBreedTypeEnum.values().length; i++) {
            breedTypeMap.put(MaterialBreedTypeEnum.values()[i].getCode(), MaterialBreedTypeEnum.values()[i].getDescription());
        }
        Date nowDate = new Date();
        Map<Integer, MainMaterialInventory> inventoryMap = new HashMap<>();
        List<MainMaterialBill> weightVoList = materialBillDao.findBreedWeight(ds.getCode(), today, breedType);
        if (weightVoList != null && weightVoList.size() > 0) {
            for (int i = 0; i < weightVoList.size(); i++) {
                MainMaterialBill weightVo = weightVoList.get(i);
                if (materialMap.containsKey(weightVo.getMaterialId())) {
                    OaMaterial material = materialMap.get(weightVo.getMaterialId());
                    Integer breed = material.getBreedType();
                    Double netWeight = StringUtils.convertDouble(weightVo.getWeight());
                    Double supplierWeight = StringUtils.convertDouble(weightVo.getSupplierWeight());
                    Double weight = 0.0;
                    if (!StringUtils.isNull(weightVo.getBillWeightType())) {
                        if (weightVo.getBillWeightType().intValue() == BillWeightTypeEnum.GF.getCode().intValue())
                            weight = supplierWeight;
                        else
                            weight = netWeight;
                    } else {
                        weight = netWeight;
                    }
                    if (inventoryMap.containsKey(breed)) {
                        MainMaterialInventory inventory = inventoryMap.get(breed);
                        inventory.setBuyWeight(inventory.getBuyWeight() + weight);
                        inventory.setSumWeight(inventory.getSumWeight() + weight);
                        inventoryMap.put(breed, inventory);
                    } else {
                        String nameNorms = StringUtils.convertString(breedTypeMap.get(breed));
                        MainMaterialInventory inventory = new MainMaterialInventory(orgId, today, startTime, endTime,
                                nameNorms, breed, 0.0, weight, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                                0.0, 0, 0);
                        inventory.setSumWeight(weight);
                        inventory.setStatus(0);
                        inventory.setCreator(creator);
                        inventory.setCreateTime(nowDate);
                        inventory.setRemark("系统同步盘存汇总数据");
                        inventoryMap.put(breed, inventory);
                    }
                }
            }
        }
        List<LabExpendVo> expendVoList = labExpendDao.findStorageExpendV1(ds.getCode(), null, null,
                null, startTime, endTime,null, breedType);
        expendVoList = convertMaterialType(expendVoList);
        if (expendVoList != null && expendVoList.size() > 0) {
            for (int i = 0; i < expendVoList.size(); i++) {
                LabExpendVo expendVo = expendVoList.get(i);
                if (materialMap.containsKey(expendVo.getMaterialId())) {
                    OaMaterial material = materialMap.get(expendVo.getMaterialId());
                    Integer breed = material.getBreedType();
                    Double realQuantity = StringUtils.convertDouble(expendVo.getRealQuantity()) * 1000;
                    Double setQuantity = StringUtils.convertDouble(expendVo.getSetQuantity()) * 1000;
                    if (inventoryMap.containsKey(breed)) {
                        MainMaterialInventory inventory = inventoryMap.get(breed);
                        inventory.setProExpend(inventory.getProExpend() + realQuantity);
                        inventory.setTheoryExpend(inventory.getTheoryExpend() + setQuantity);
                        inventoryMap.put(breed, inventory);
                    } else {
                        String nameNorms = StringUtils.convertString(breedTypeMap.get(breed));
                        MainMaterialInventory inventory = new MainMaterialInventory(orgId, today, startTime, endTime,
                                nameNorms, breed, 0.0, 0.0, 0.0,
                                realQuantity, setQuantity, 0.0, 0.0, 0.0, 0.0, 0.0,
                                0.0, 0, 0);
                        inventory.setStatus(0);
                        inventory.setCreator(creator);
                        inventory.setRemark("系统同步盘存汇总数据");
                        inventory.setCreateTime(nowDate);
                        inventoryMap.put(breed, inventory);
                    }
                }
            }
        }
        List<MainMaterialInventoryDetail> inventoryList = inventoryDetailDao.findBreedInventory(ds.getCode(), today, breedType);
        if (inventoryList != null && inventoryList.size() > 0) {
            for (int i = 0; i < inventoryList.size(); i++) {
                MainMaterialInventoryDetail detail = inventoryList.get(i);
                if (materialMap.containsKey(detail.getMaterialId())) {
                    OaMaterial material = materialMap.get(detail.getMaterialId());
                    Integer breed = material.getBreedType();
                    Double weight = StringUtils.convertDouble(detail.getWeight());
                    if (inventoryMap.containsKey(breed)) {
                        MainMaterialInventory inventory = inventoryMap.get(breed);
                        inventory.setInventory(inventory.getInventory() + weight);
                        inventoryMap.put(breed, inventory);
                    } else {
                        String nameNorms = StringUtils.convertString(breedTypeMap.get(breed));
                        MainMaterialInventory inventory = new MainMaterialInventory(orgId, today, startTime, endTime,
                                nameNorms, breed, 0.0, 0.0, 0.0,
                                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                                weight, 0, 0);
                        inventory.setStatus(0);
                        inventory.setCreator(creator);
                        inventory.setRemark("系统同步盘存汇总数据");
                        inventory.setCreateTime(nowDate);
                        inventoryMap.put(breed, inventory);
                    }
                }
            }
        }
        if (inventoryMap == null || inventoryMap.keySet().size() == 0)
            throw new MessageCenterException("没有汇总统计数据");
        String nowTime = today + "-01 08:30:00";
        String beforeTime = DateUtil.convertString(DateUtil.convertBeforeMonthDate(DateUtil.convertDate(nowTime), 1));
        String beforeToday = beforeTime.substring(0,7);//上个月的统计月份
        for (Integer breed : inventoryMap.keySet()) {
            MainMaterialInventory inventory = inventoryMap.get(breed);
            if (inventory == null)
                continue;
            Double lastStorage = 0.0;
            MainMaterialInventory hisInventory = materialInventoryDao.findTodayBreed(orgId, beforeToday, breed);
            if (hisInventory != null) {
                lastStorage = hisInventory.getInventory();
            }
            Double sumExpend = StringUtils.convertDouble(inventory.getSumExpend());
            if (!StringUtils.isNull(inventory.getHandExpend())) {//手动消耗
                sumExpend = inventory.getHandExpend() + StringUtils.convertDouble(inventory.getProExpend());
                inventory.setSumExpend(StringUtils.formatDouble(sumExpend, 1));
            } else {
                inventory.setSumExpend(inventory.getProExpend());
            }
            //本月帐存=(上月结余+本月进货)-本月消耗；
            // 盈亏=本月盘存-本月帐存；调整后消耗=(上月结余+本月进货)-本月盘存；
            // 其中本月消耗=拌台系统消耗数或理论计算消耗数
            Double inventoryDosage = StringUtils.convertDouble(inventory.getInventory());//盘存值
            Double sumWeight = StringUtils.convertDouble(inventory.getBuyWeight()) + StringUtils.convertDouble(inventory.getAddWeight());
            Double monthStorage = lastStorage + sumWeight - sumExpend;
            Double difference = StringUtils.formatDouble(inventoryDosage - monthStorage, 1);//盈亏
            Double adjustExpend = lastStorage + sumWeight - inventoryDosage;
            inventory.setLastStorage(lastStorage);
            inventory.setMonthStorage(StringUtils.formatDouble(monthStorage, 1));//本月账存
            inventory.setDifference(difference);
            inventory.setAdjustExpend(adjustExpend);

            MainMaterialInventory existInventory = materialInventoryDao.findTodayBreed(orgId, today, breed);
            if (existInventory != null) {
                if (!StringUtils.isNull(inventory.getIsCheck()) && inventory.getIsCheck() == 1)
                    continue;
                inventory.setId(existInventory.getId());
                inventory.setUpdator(creator);
                inventory.setUpdateTime(nowDate);
                materialInventoryDao.updateById(inventory);
            } else {
                materialInventoryDao.insert(inventory);
            }
        }
        return RestResultDto.success("同步完成,请5分钟后刷新再试");
    }
    /**
     * 查询是否已审核
     * @param orgId
     * @param today
     * @return
     */
    public Integer findCheck(Long orgId, String today) {
        if (StringUtils.isAllParamNull(orgId, today))
            throw new MessageCenterException("查询审核信息参数错误");
        Integer total = materialInventoryDao.findCheckTotal(orgId, today, 1, null);
        if (total > 0)
            return total;
        total = materialInventoryDao.findCheckTotal(orgId, today, null, 1);
        if (total > 0)
            return total;
        return 0;
    }
    /**
     * 审核盘存汇总
     * @param orgId
     * @param today
     * @param creator
     * @param type 0 材料审核 1 财务审核
     * @return
     */
    public RestResultDto examineInventory(Long orgId, String today, String creator, Integer type) {
        if (StringUtils.isAllParamNull(orgId, today, type))
            throw new MessageCenterException("参数错误");
        if (type == 0) {
            QueryWrapper<MainMaterialInventory> query = new QueryWrapper<>();
            query.eq("org_id", orgId);
            query.eq("today", today);
            query.eq("status", 0);
            query.eq("is_check", 0);
            Integer total = materialInventoryDao.selectCount(query);
            if (total < 1)
                throw new MessageCenterException("没有需要审核的数据");
            Date nowDate = new Date();
            UpdateWrapper<MainMaterialInventory> uw = new UpdateWrapper<>();
            uw.set("is_check", 1);
            uw.set("checker", creator);
            uw.set("check_time", DateUtil.convertString(nowDate));
            uw.set("updator", creator);
            uw.set("update_time", DateUtil.convertString(nowDate));
            uw.eq("org_id", orgId);
            uw.eq("today", today);
            uw.eq("is_check", 0);
            Integer code = materialInventoryDao.update(new MainMaterialInventory(), uw);
            if (code > 0)
                return RestResultDto.success("审核成功");
        } else if (type == 1) {
            QueryWrapper<MainMaterialInventory> query = new QueryWrapper<>();
            query.eq("org_id", orgId);
            query.eq("today", today);
            query.eq("status", 0);
            query.eq("is_finance", 0);
            Integer total = materialInventoryDao.selectCount(query);
            if (total < 1)
                throw new MessageCenterException("没有需要审核的数据");
            query = new QueryWrapper<>();
            query.eq("org_id", orgId);
            query.eq("today", today);
            query.eq("status", 0);
            query.eq("is_check", 0);
            total = materialInventoryDao.selectCount(query);
            if (total > 0)
                throw new MessageCenterException("需材料统计审核后方可审核");
            Date nowDate = new Date();
            UpdateWrapper<MainMaterialInventory> uw = new UpdateWrapper<>();
            uw.set("is_finance", 1);
            uw.set("finance", creator);
            uw.set("finance_time", DateUtil.convertString(nowDate));
            uw.set("updator", creator);
            uw.set("update_time", DateUtil.convertString(nowDate));
            uw.eq("org_id", orgId);
            uw.eq("today", today);
            uw.eq("is_finance", 0);
            Integer code = materialInventoryDao.update(new MainMaterialInventory(), uw);
            if (code > 0)
                return RestResultDto.success("审核成功");
        }
        throw new MessageCenterException("审核类型错误");
    }
    /**
     * 转换材料类型
     * @param expendList
     * @return
     */
    private List<LabExpendVo> convertMaterialType(List<LabExpendVo> expendList) {
        if (expendList == null || expendList.size() == 0)
            return null;
        List<LabExpendVo> resultList = new ArrayList<>();
        Map<Long, LabExpendVo> expendVoMap = new LinkedHashMap<>();
        for (int i = 0; i < expendList.size(); i++) {
            LabExpendVo expendVo = expendList.get(i);
            Long materialId = expendVo.getMaterialId();
            if (expendVoMap.containsKey(materialId)) {
                LabExpendVo tempVo = expendVoMap.get(materialId);
                Double labQuantity = StringUtils.formatDouble(StringUtils.convertDouble(tempVo.getLabQuantity()) * 1000 + StringUtils.convertDouble(expendVo.getLabQuantity()) * 1000, 2);
                Double setQuantity = StringUtils.formatDouble(StringUtils.convertDouble(tempVo.getSetQuantity()) * 1000 + StringUtils.convertDouble(expendVo.getSetQuantity()) * 1000, 2);
                Double realQuantity = StringUtils.formatDouble(StringUtils.convertDouble(tempVo.getRealQuantity()) * 1000 + StringUtils.convertDouble(expendVo.getRealQuantity()) * 1000, 2);
                Double errorValue = StringUtils.formatDouble(realQuantity - labQuantity, 2);
                Double errorRate = 0.0;
                if (!StringUtils.isNull(errorValue) && errorValue != 0
                        && !StringUtils.isNull(labQuantity) && labQuantity.doubleValue() != 0)
                    errorRate = StringUtils.formatDouble(StringUtils.convertDouble(errorValue) / StringUtils.convertDouble(labQuantity), 2);
                tempVo.setLabQuantity(labQuantity);
                tempVo.setSetQuantity(setQuantity);
                tempVo.setRealQuantity(realQuantity);
                tempVo.setErrorValue(errorValue);
                tempVo.setErrorRate(errorRate);
                expendVoMap.put(materialId, tempVo);
            } else {
                expendVoMap.put(materialId, expendVo);
            }
        }
        for (Long key : expendVoMap.keySet()) {
            resultList.add(expendVoMap.get(key));
        }
        return resultList;
    }
}